﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Xml.Serialization;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using BrainTechLLC.ThreadSafeObjects;
using System.Runtime.Serialization;
using System.Reflection;
#if USE_HYPER
using Hyper.ComponentModel;
#endif

namespace BrainTechLLC
{
    public delegate List<SingleInfluence> GetInfluenceDelegate(ExternalInfluence influence, IGameThing influenceCause, IGameThing eventSource, IGameThing target, Dictionary<string, IdentifierAndValue> parameters);

    public interface ICanRegisterInfluence : IGameThing
    {
        ExternalInfluence CreateRegisteredInfluence(ICanRegisterInfluence cause, IGameThing associatedGameThing);
    }

    public interface ICanBeInfluenced : IHasInfluenceCollection
    {
        //void RegisterInfluence(ICanRegisterInfluence cause);
        //void RemoveInfluence(ICanRegisterInfluence cause);
    }

    public interface IHasInfluenceCollection : IGameThing
    {
        InfluenceCollection InfluenceCollection { get; }
    }

    [Serializable]
    //[DataContract]
    public class InfluenceCollection : AssociatedIDCollection
    {
        [NonSerialized, XmlIgnore]
        protected ThreadSafeListAndLookup<string, ExternalInfluence> _influencesByName;

        [XmlIgnore]
        public virtual ThreadSafeListAndLookup<string, ExternalInfluence> InfluencesByName
        {
            get
            {
                if (Modified)
                {
                    Modified = false;
                    Interlocked.Exchange<ThreadSafeListAndLookup<string, ExternalInfluence>>(ref _influencesByName, null);
                }

                if (_influencesByName == null)
                {
                    Interlocked.CompareExchange<ThreadSafeListAndLookup<string, ExternalInfluence>>(
                        ref _influencesByName,
                        new ThreadSafeListAndLookup<string, ExternalInfluence>(ReadItems<ExternalInfluence>(), (v) => v.InfluenceEvent),
                        null);
                }
                return _influencesByName;
            }
            set { _influencesByName = value; }
        }

        public void Add(ExternalInfluence influence)
        {
            Add(influence.AssociatedID);
        }

        public Dictionary<string, IdentifierAndValue> AccountForInfluences(string influencableName, IGameThing eventSource, IGameThing target, PropertyData parameters)
        {
            Dictionary<string, IdentifierAndValue> all = new Dictionary<string, IdentifierAndValue>();

            // HEREHERE
            foreach (var v in parameters.Props.AllItems)
            {
                all.Add(v.Identifier, v);
            }

            List<ExternalInfluence> influences = InfluencesByName.Find(influencableName);
            influences.Sort((a, b) => a.Priority.CompareTo(b.Priority));

            for (int n = 0; n < influences.Count; n++)
            {
                ExternalInfluence influence = influences[n];
                IGameThing cause = Everything.Find<IGameThing>(influence.CausedByID);
                List<SingleInfluence> results = influence.GetInfluenceMethod(influence, cause, eventSource, target, all);
                if (results != null)
                {
                    for (int i = 0; i < results.Count; i++)
                    {
                        SingleInfluence infl = results[i];
                        if (!all.ContainsKey(infl.InfluencesParameter))
                        {
                            all.Add(infl.InfluencesParameter, new IdentifierAndValue(infl.InfluencesParameter, infl.NewValue.Value));
                        }
                        else
                        {
                            all[infl.InfluencesParameter].Value = infl.NewValue.Value;
                        }
                    }
                }
            }

            return all;
        }

        public List<ExternalInfluence> RemoveInfluenceAssociatedWith(long id)
        {
            List<ExternalInfluence> influencesRemoved = InfluencesByName.Remove((v) => v.CausedByID == id);
            return influencesRemoved;
        }
    }

    public class InfluenceManager : InfluenceCollection
    {
        [XmlIgnore]
        public override ThreadSafeListAndLookup<string, ExternalInfluence> InfluencesByName
        {
            get
            {
                if (_influencesByName == null)
                    Interlocked.CompareExchange<ThreadSafeListAndLookup<string, ExternalInfluence>>(ref _influencesByName, new ThreadSafeListAndLookup<string, ExternalInfluence>(), null);

                return _influencesByName;
            }
            set
            {
                _influencesByName = value;
            }
        }

        public void Register(ExternalInfluence influence)
        {
            InfluencesByName.Add(influence.InfluenceEvent, influence);
        }

        public static bool RemoveInfluence(ICanRegisterInfluence influenceRegister, ICanBeInfluenced target)
        {
            if (influenceRegister != null && target != null)
            {
                target.InfluenceCollection.RemoveInfluenceAssociatedWith(influenceRegister.AssociatedID);
                return true;
            }

            return false;
        }

        public static bool RegisterInfluence(ICanRegisterInfluence influenceRegister, ICanBeInfluenced target)
        {
            if (influenceRegister != null && target != null)
            {
                ExternalInfluence influence = influenceRegister.CreateRegisteredInfluence(influenceRegister, target);

                if (influence != null)
                {
                    target.InfluenceCollection.InfluencesByName.Add(influence.InfluenceName, influence);
                    return true;
                }                
            }
            return false;
        }
    }

    public class TestDoubleDamageInfluence
    {
        public static List<SingleInfluence> GetDoubleDamageInfluence(ExternalInfluence influence, IGameThing influenceCause, IGameThing eventSource, IGameThing target, Dictionary<string, IdentifierAndValue> parameters)
        {
            List<SingleInfluence> results = new List<SingleInfluence>();
            IdentifierAndValue original = parameters["DamagePhysical"];
            SingleInfluence single = new SingleInfluence()
            {
                InfluencesParameter = "DamagePhysical",
                NewValue = new IdentifierAndValue("DamagePhysical", Convert.ToInt32(original.Value) * 2)
            };
            results.Add(single);
            return results;
        }
    }
}